package com.settlement.system.common.util.common;

import com.settlement.system.common.enums.Code;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.lang.Nullable;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 描述: 枚举工具类 <br>
 * tool:<br>
 *   泛型多个要求: &lt;T extends Enum&lt;T&gt; &amp; Code&gt;<br>
 * @author hc <br>
 */
@NoArgsConstructor(access=AccessLevel.PRIVATE)
public class EnumUtil {
	/**
	 * 判断num是否在枚举里面
	 * <code>
	 *    eq(null,Enum)=false;<br/>
	 *    eq(0,null)=false;<br/>
	 * </code>
	 * @param num 状态数字
	 * @param e 对应的枚举
	 * @return !(num==null || e==null) && e.ordinal()==num 结果
	 */
	public static boolean eqEnum(@Nullable Integer num, Enum<?> e){
		return !(num==null || e==null) && e.ordinal()==num;
	}

	/**
	 * 判断num是否在枚举里面
	 * @param num 状态数字
	 * @param ins 对应的枚举
	 * @return 判断num是否在枚举里面
	 */
	public static boolean inEnum(@Nullable Integer num,Enum<?>... ins){
		if(num==null || ins==null || ins.length<1){
			return false;
		}
		for(Enum<?> e:ins){
			if(e!=null&&e.ordinal()==num){return true;}
		}
		return false;
	}
	/**
	 * 判断枚举是否在枚举数组里面
	 * @param target 目标枚举
	 * @param ins 对应的枚举
	 * @return 判断枚举是否在枚举数组里面
	 */
	public static boolean enumInEnums(@Nullable Enum<?> target,Enum<?>... ins){
		if(target==null || ins==null || ins.length<1){
			return false;
		}
		for(Enum<?> e:ins){
			if(target.equals( e )){return true;}
		}
		return false;
	}
	/**
	 * 代码是否等于枚举
	 * @param code 代码标示,例如type/status
	 * @param en 枚举
	 * @param <C> 代码类型,例如String/Integer
	 * @param <E> 枚举,继承Code
	 * @return 代码是否等于枚举,一方为null/都是null,返回false
	 */
	public static <C extends Serializable,E extends Enum<E> & Code<C>> boolean eq(@Nullable C code, E en){
		if(code==null){return false;}
		if(en==null){return false;}

		return code.equals( en.code() );
	}

	/**
	 * 代码是否在枚举数组中
	 * @param code 代码标示,例如type/status
	 * @param es 枚举
	 * @param <C> 代码类型,例如String/Integer
	 * @param <E> 枚举,继承Code
	 * @return 代码是否在枚举数组中
	 */
	@SafeVarargs
	public static <C extends Serializable,E extends Enum<E> & Code<C>> boolean in(@Nullable C code, E... es){
		if(code==null || es==null || es.length<1){
			return false;
		}
		for(E e:es){
			if(eq(code,e)){
				return true;
			}
		}
		return false;
	}

	/**
	 * 通过唯一标识code获取枚举
	 * @param code 枚举唯一标识code
	 * @param enumClass 枚举
	 * @param defaultEnum 默认值
	 * @param <C> 枚举唯一标识code类型
	 * @param <E> 枚举类型
	 * @return 通过唯一标识code获取枚举
	 */
	public static <C extends Serializable,E extends Enum<E> & Code<C>> E witch(@Nullable C code,Class<E> enumClass,E defaultEnum){
		if(code==null){
			return defaultEnum;
		}
		E[] values=enumClass.getEnumConstants();
		for(E e:values){
			if( eq( code,e ) ){
				return e;
			}
		}
		return defaultEnum;
	}

	/**
	 * 通过唯一标识code获取枚举
	 * @param code 枚举唯一标识code
	 * @param enumClass 枚举
	 * @param defaultEnum 默认值
	 * @param <E> 枚举类型
	 * @return 通过唯一标识code获取枚举
	 */
	public static <E extends Enum<E> & Code<Integer>> E witchByInteger(@Nullable Integer code,Class<E> enumClass,E defaultEnum){
		if(code==null||code<0){
			return defaultEnum;
		}
		return witch( code,enumClass,defaultEnum );
	}


	/**
	 * 枚举to list
	 * @param es 枚举
	 * @param <C> 代码类型,例如String/Integer
	 * @param <E> 枚举,继承Code
	 * @return 代码是否在枚举数组中
	 */
	@SafeVarargs
	public static <C extends Serializable,E extends Enum<E> & Code<C>> List<C> toList(E... es){
		if(es==null || es.length<1){
			return Collections.emptyList();
		}
		List<C> set=new ArrayList<>(16);
		for(E e:es){
			if(e!=null){
				set.add( e.code() );
			}
		}
		return set;
	}

	/**
	 * 枚举to list
	 * @param enumClass 枚举
	 * @param <C> 枚举唯一标识code类型
	 * @param <E> 枚举类型
	 * @return 通过唯一标识code获取枚举
	 */
	public static <C extends Serializable,E extends Enum<E> & Code<C>> List<C> toList(Class<E> enumClass){
		E[] values=enumClass.getEnumConstants();
		return toList(values);
	}
	/**
	 * 枚举to list
	 * @param es 枚举
	 * @param <C> 代码类型,例如String/Integer
	 * @param <E> 枚举,继承Code
	 * @return 代码是否在枚举数组中
	 */
	public static <C extends Serializable,E extends Enum<E> & Code<C>> List<C> toList(List<E> es){
		if(es==null || es.isEmpty()){
			return Collections.emptyList();
		}
		List<C> set=new ArrayList<>(16);
		for(E e:es){
			if(e!=null){
				set.add( e.code() );
			}
		}
		//这样会报错,es.stream().map(e -> e.code()).collect(Collectors.toList())
		return set;
	}

	/**
	 * 大于等于0
	 * @param num 数字
	 * @return 是否大于等于0
	 */
	public static boolean isIntCode(Integer num){
		return num!=null&&num>=0;
	}
}
